package com.lkm.market2_0.m_imple.steelyardserver.server;

import com.google.gson.Gson;
import com.lkm.frame.P;
import com.lkm.frame.task.ProgressData;
import com.lkm.frame.task.ProgressDataImpl;
import com.lkm.frame.task2.ITaskExecutor;
import com.lkm.frame.task2.InterceptorAdapter;
import com.lkm.frame.task2.Task;
import com.lkm.frame.task2.TaskAdapter;
import com.lkm.frame.task2.TaskManager;
import com.lkm.hardware_connect.HardwareControlerHelp;
import com.lkm.hardware_connect.IHardwareControler;
import com.lkm.javatool.NumberHelp;
import com.lkm.javatool.StringHelp;
import com.lkm.javatool.lang.RunnablePR;
import com.lkm.market2_0.ExpandConfig;
import com.lkm.market2_0.help.UIP;
import com.lkm.market2_0.m_imple.steelyardserver.server.cmd_handle.CMDHeartbeatHandle;
import com.lkm.market2_0.m.steelyardstatus.StatusInfo;
import com.lkm.market2_0.m.steelyardstatus.SteelyardStatusManagerModule;
import com.lkm.market2_0.m_imple.steelyardserver.server.cmd_handle.CMDKeyHandle;

import java.util.Arrays;
import java.util.concurrent.LinkedBlockingQueue;




public abstract class ReceiveTask extends TaskAdapter<IHardwareControler, Object, Void> {

    public static String createId(String clientSessionId){
        return "readTask"+clientSessionId;
    }

    private SteelyardStatusManagerModule mSteelyardStatusManagerModule;
//    clientSessionId 应该保证每次都不一样。不然本次第一个心跳就会取消本次的task，见com.lkm.market2_0.steelard_server.ReceiveTask.firstHeartbeat
    public String clientSessionId; 
    private String steelyardCupCode;
    public String  steelyardMac;
    public StatusInfo statusInfo;
    private boolean isNio;

    public boolean isNio() {
        return isNio;
    }

    

    public ReceiveTask(ITaskExecutor<IHardwareControler, Object, Void> taskExecutor, TaskManager mTaskManager, String clientSessionId,SteelyardStatusManagerModule steelyardStatusManagerModule, boolean isNio) {
        super(taskExecutor, ReceiveTask.class.getName(), mTaskManager);
        this.clientSessionId=clientSessionId;
        this.mSteelyardStatusManagerModule=steelyardStatusManagerModule;
        this.isNio = isNio;
    }

    @Override
    public Object call(int cmd, Object data) {
        if (cmd == 1) {
           return receiveData((byte[])data);
        }





        return super.call(cmd, data);
    }

    

    public int receiveData(byte [] data){
        int size = receiveData._2(null);
        if(size == -1){
            receiveData._1();
        }
        return receiveData._2(data);
    }


    @Override
    public void doExecuting(IHardwareControler param) {
        super.doExecuting(param);
        if(isNio){
            receiveData._1();
        }else
        mTaskExecutor.executor(new RunnablePR<IHardwareControler, Void>() {
            @Override
            public Void run(IHardwareControler bluetoothSocket) {
                doAsyncExecuting(bluetoothSocket);
                return null;
            }
        }, param);
    }

    
    private volatile AbsReceiverDataHandle mReceiverDataHandle;


    private class ReceiveData{
        AbsReceiverDataHandle receiverDataInfoTemp ;
        int readInMax;

        
        
        public void _1() {
            state = 0;
            receiverDataInfoTemp = mReceiverDataHandle;
            readInMax = 0;
            
            if (receiverDataInfoTemp != null) {
                readInMax = receiverDataInfoTemp.getReadFrameDataSize();
            } else {

                readInMax = 38 - 3;
            }
            if (P.isDebug() && false) {
                P.p("======read readInMax " + readInMax);
                if (UIP.isPrint()) {
                    UIP.p("read 等待读取数据 " + readInMax, steelyardCupCode);
                }
            }
        }











        byte state = -1;
        int readHeadCount = 0;


        

        public int _2(byte[] in) {

            if(state == -1){
                return -1;
            }
            if(state == 4){
                return -1;
            }
            if(in==null){
                
                if(receiverDataInfoTemp == null){
                    
                    if(state !=3){
                        return 1;
                    }else{
                        
                        return readInMax;
                    }
                }
                return readInMax;
            }

            
            if(readInMax == in.length){
                readOK(in);
                state = 4;
                return -1;
            }else if(receiverDataInfoTemp == null&&in.length==1){  
                if(checkHeard(in[0])){
                    return readInMax;
                }else {
                    return 1;
                }
            }else {
                
                return readInMax;
            }

        }
        private void readOK(byte[] in){
            byte [] data =null;
            if(receiverDataInfoTemp == null){
                
                data=concatbyte(new byte[]{(byte)0x55,(byte)0xaa,(byte)0x26},in);
            }else {
                
                data = in;
            }
            
            _3(data);
        }
        
        private boolean checkHeard(byte fdata){

            if(state==(byte)0){
                if(fdata == (byte) 0x55){
                    
                    state = 1;
                }
            }else if(state == (byte)1){
                if(fdata == (byte) 0xAA){
                    
                    state = 2;
                }
            }else if(state == (byte)2){
                if(fdata == (byte) 0x26){
                    
                    state = 3;
                }
                readHeadCount = 0;
                
                return true ;
            }
            readHeadCount++;
            
            if(P.isDebug()&&readHeadCount>2) {
                String logs = "接受数据，无意义的数据，个数："+readHeadCount;
                P.p("=====" +logs);
                if(UIP.isPrint()){
                    UIP.p(logs,steelyardCupCode);
                }
            }
            return false;
        }

        

        private void _3(byte []data){



            
            if (P.isDebug()&&false) {

                StringBuilder stringBuilder=new StringBuilder();
                for(byte b:data){
                    stringBuilder.append(" ");
                    stringBuilder.append(NumberHelp.bytesToHex(b));
                }

                String logs="收到长度 "+readInMax+"   "+stringBuilder.toString();
                P.p("====="+logs);
                if(UIP.isPrint()){
                    UIP.p("接受数据："+logs,steelyardCupCode);
                }
            }

            
            if (receiverDataInfoTemp != null) {


                int max=receiverDataInfoTemp.getLength()/receiverDataInfoTemp.getReadFrameDataSize();

                int index=receiverDataInfoTemp.getReceiverLengthCount()/receiverDataInfoTemp.getReadFrameDataSize();

                receiverDataInfoTemp.setReceiverLengthCount(receiverDataInfoTemp.getReceiverLengthCount() + readInMax);

                try {
                    receiverDataInfoTemp.handleData(ReceiveTask.this, data, index, max);
                }catch (Throwable throwable){
                    
                    throwable.printStackTrace();
                }
                
                if (receiverDataInfoTemp.getLength() <= receiverDataInfoTemp.getReceiverLengthCount()) {
                    mReceiverDataHandle = null;
                }
            } else {
                

                
                if (
                        data[0] == 85
                                && data[1] == -86
                                && data[2] == 38
                                && data[data.length - 1] == 13
                ) {
                    CMDEntity cmdEntity = null;
                    
                    
                    cmdEntity = CMDEntity.parserByData(steelyardCupCode,Arrays.copyOfRange(data, 3, data.length - 2));

                    
                    byte checkNum= data[3];
                    checkNum+=data[4];
                    checkNum+=data[5];
                    if(cmdEntity.getData()!=null)
                        for (byte b:cmdEntity.getData()){
                            checkNum+=b;
                        }
                    

                    byte checkNumb=checkNum;
                    if(checkNumb==data[data.length - 2]) {

                        ICMDHandle cmdHandle = createICMDHandleByCMDEntity(cmdEntity);

                        
                        if (cmdHandle != null) {

                            if(!StringHelp.isEmpty(steelyardCupCode))   {

                                statusInfo=mSteelyardStatusManagerModule.getStatusInfoBySteelyardMac(steelyardCupCode);
                                
                                mSteelyardStatusManagerModule.receiver(steelyardCupCode, System.currentTimeMillis(), statusInfo==null?false:statusInfo.isException(), statusInfo==null?"":statusInfo.getVersion(),statusInfo==null?"":statusInfo.getNumno(),statusInfo==null?0:statusInfo.getVoltage());
                            }

                            try {
                                
                                if(StringHelp.isEmpty(steelyardCupCode))   {
                                    
                                    if(cmdHandle instanceof CMDHeartbeatHandle){
                                        
                                        mReceiverDataHandle = ((CMDHeartbeatHandle)cmdHandle).handle(cmdEntity, new RunnablePR<String, Void>() {
                                            @Override
                                            public Void run(String s) {
                                                firstHeartbeat(s);
                                                return null;
                                            }
                                        });
                                    }
                                    if(ExpandConfig.instance.isUI()){
                                        
                                        if(cmdHandle instanceof CMDKeyHandle){
                                            mReceiverDataHandle = cmdHandle.handle(cmdEntity);
                                        }
                                    }
                                }else{
                                    
                                    mReceiverDataHandle = cmdHandle.handle(cmdEntity);
                                }
                            } catch (Throwable throwable) {
                                
                                throwable.printStackTrace();
                            }
                        }

                        
                        if (mReceiverDataHandle != null) {
                            
                            progressUpdate(new ProgressDataImpl<Object>(0, 0, mReceiverDataHandle));
                        } else {
                            
                            progressUpdate(new ProgressDataImpl<Object>(0, 0, cmdEntity));
                        }
                    }else{
                        
                        if(P.isDebug()) {
                            String log="=====校验和出错：" + steelyardCupCode + "  收到：" + NumberHelp.bytesToHex(data[data.length - 2]) + "  应该为：" + NumberHelp.bytesToHex(checkNumb);
                            P.p(log);
                            if(UIP.isPrint()){
                                UIP.p(log,steelyardCupCode);
                            }
                        }
                    }

                } else {
                    
                }

            }

            tryWriteTask();
        }

    }

    private ReceiveData receiveData = new ReceiveData();
    
    private void doAsyncExecuting(IHardwareControler param) {
        IHardwareControler mBluetoothSocket = param;

        if (P.isDebug())
            P.p("======read  开始读取");
        while (getIsContinue() && mBluetoothSocket.isConnected()) {

            receiveData._1();

            byte[] data = null;
            int readSize = receiveData._2(null);
            
            while (getIsContinue() && mBluetoothSocket.isConnected()) {

                if(readSize == -1){
                    break;
                }
                try {
                    data = HardwareControlerHelp.readFull(mBluetoothSocket, readSize);
                } catch (Exception e) {
                    data = null;
                    if(P.isDebug()) {
                        e.printStackTrace();
                    }
                }
                if (data == null) {
                    break;
                }
                readSize = receiveData._2(data);

            }
            
            if (data == null && readSize > 0) {
                
                if(P.isDebug()) {
                    P.d("连接已经断开：%s" ,steelyardCupCode);
                    if (UIP.isPrint()) {
                        UIP.p("连接已经断开：" ,steelyardCupCode);
                    }
                }
                break;
            }
        }

        if(statusInfo!=null)
            statusInfo.setDisConnect(true);
        
        complete(null);
    }

    

    protected void firstHeartbeat(String steelyardMac_ ){
        steelyardCupCode=steelyardMac = steelyardMac_ ;
        ReceiveTask receiveTask = findReceiveTaskBySteelyardMac(steelyardMac_);

        
        if(receiveTask!=null){
            receiveTask.cancel();
        }
        


        
        ClientSessionMap.getInstance().put(steelyardCupCode,clientSessionId);

//        if(com.lkm.market2_0.Config.instance.isUI()){



    }
    private ReceiveTask findReceiveTaskBySteelyardMac(String steelyardMac){

        String clientSessionId= ClientSessionMap.getInstance().getClientSessionIdBysteelyardMac(steelyardMac);

        TaskManager taskManager= ExpandConfig.instance.getTaskManager2();

        int[] ses=taskManager.getRunTask(ReceiveTask.createId(clientSessionId));

        ReceiveTask receiveTask=null;
        if(ses!=null){
            receiveTask = (ReceiveTask)taskManager.getRunTask(ses[0]);
        }
        return receiveTask;
    }

    public static  byte[] concatbyte(byte[] first, byte[] second) {
        byte[] result = Arrays.copyOf(first, first.length + second.length);
        System.arraycopy(second, 0, result, first.length, second.length);
        return result;
    }

    private volatile Task curWriteTask=null;
    private LinkedBlockingQueue<AbsSendWriteTask> writeLinkedBlockingQueue=new LinkedBlockingQueue<AbsSendWriteTask> ();

    

    public synchronized void requertWriteTask(AbsSendWriteTask writeTask){
        try {
            writeLinkedBlockingQueue.put(writeTask);
            tryWriteTask();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    

    private synchronized void tryWriteTask(){
        
        if(mReceiverDataHandle!=null){
            
        }else{

            if(curWriteTask==null||!curWriteTask.getIsContinue()||curWriteTask.isComplete()) {
                AbsSendWriteTask nextTask = writeLinkedBlockingQueue.poll();
                curWriteTask=nextTask;
                
                if (nextTask != null) {
                    nextTask.addInterceptor(new InterceptorAdapter(){

                        @Override
                        public boolean onInterceptEnd(Task task, boolean isCancel, Object o) {
                            tryWriteTask();
                            return super.onInterceptEnd(task, isCancel, o);
                        }

                        
                        @Override
                        public boolean interceptComplete(Task task, Object result) {
                            tryWriteTask();
                            return super.interceptComplete(task, result);
                        }
                    });

                    nextTask.send();
                }
            }
        }
    }


    @Override
    public boolean interceptCancel(Task<IHardwareControler, ?, Void> task) {
        
        try {
            getParam().close();
        } catch (Exception e) {
        }
        return super.interceptCancel(task);
    }

    @Override
    public boolean interceptComplete(Task<IHardwareControler, ?, Void> task, Void result) {
        
        try {
            getParam().close();
        } catch (Exception e) {
        }
        return super.interceptComplete(task, result);
    }

    @Override
    public boolean interceptProgressUpdate(Task<?, Object, ?> task, ProgressData<Object> progressData) {
        

        Object data = progressData.getData();
        
        if (data instanceof AbsReceiverDataHandle) {

            
            tickOK();
        }else if (data instanceof CMDEntity){
            CMDEntity cmdEntity=(CMDEntity)data;
            

            if(((CMDEntity) data).isTickCMD()){
                if(P.isDebug())
                //P.d("=====发送 收到回答"+((CMDEntity) data).isTickCMD());
                if(curWriteTask!=null)
                    curWriteTask.orderCmd(0,cmdEntity);
            }

        }



        return true;
    }


    
    public void tickOK(){
        boolean isTickOk=true;
        IHardwareControler socket=getParam();

        byte[] data=new byte[38];
        Arrays.fill(data,(byte) 0);
        data[0]=0x55;
        data[1]=(byte)0xAA;
        data[2]=0x26;
        data[data.length-1]=0x0D;
        if(isTickOk){
            data[3]=(byte)0x00;
            data[data.length-2]=(byte)0x00;
        }else{
            data[3]=(byte)0xff;
            data[data.length-2]=(byte)0xff;
        }

        int writeSize=-1;
        try {
            if(P.isDebug()&&false)
                P.p(new Gson().toJson(data));
            writeSize=socket.write(data);
        }catch (Exception e){
            writeSize=-1;
            e.printStackTrace();
        }
        if(P.isDebug()&&false)
            P.p("===写入长度："+writeSize);



    }

    @Override
    public boolean onInterceptEnd(boolean isCancel, Void result) {
        if(P.isDebug()) {
            if (UIP.isPrint()) {
                UIP.p("结束接待：" , steelyardCupCode);
            }
        }

        return super.onInterceptEnd(isCancel, result);
    }

    @Override
    public boolean onInterceptPreExecute(Task<IHardwareControler, ?, Void> task) {

        return super.onInterceptPreExecute(task);
    }

    protected abstract ICMDHandle  createICMDHandleByCMDEntity(CMDEntity cmdEntity);


    

    public IHardwareControler getIHardwareControler(){
        return getParam();
    }




}
